perm filename HELP.DOC[AID,LSP]1 blob
sn#478994 filedate 1980-08-10 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00017 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 Debugging Aids in LISP
C00005 00003 THE LISP EDITOR
C00028 00004 The Backspace (BS) Package
C00035 00005 The BRAKE Package
C00041 00006 THE DEBUG PACKAGE
C00054 00007 THE STEP PACKAGE
C00068 00008 Features and Meta-features
C00071 00009 String
C00075 00010 MACRO
C00080 00011 Further MACRO/MACRODEF features
C00082 00012 MACEX
C00083 00013 REQUIRE
C00085 00014 DIRECT
C00087 00015 ET
C00088 00016 MAIL
C00089 00017 Line Editor Loading
C00090 ENDMK
C⊗;
Debugging Aids in LISP
--------- ---- -- ----
The following is a description of some of the more
sophisticated debugging aids available in MACLISP at SAIL.
Covered in this memo are:
1. The LISP Editor, written by R.P.Gabriel and T.Finin
2. The Backspace package, written by Jonl White
3. The Brake package, written by R.P.Gabriel
4. The Stepper package, written by R.P. Gabriel and Tim Finin
5. The Debug package, written by R.P. Gabriel and T.Finin.
6. Random debugging features and meta-features.
In each case, the programs are FASLOADable and are
located on the DSK [MAC,LSP] under EDIT.FAS, BS.FAS, BRAKE.FAS,
STEP.FAS and DEBUG.FAS respectively.
In addition, the file HELP.FAS DSK [MAC LSP] can be FASLOADed
into a LISP to setup "autoload" pointers to all of the
debugging functions mentioned in this memo. Then, whenever
any of these functions is called, the appropriate file will
be automatically loaded.
THE LISP EDITOR
--- ---- ------
The following is a very brief introduction to the use
of the LISP Editor.
Loading the Editor
------- --- ------
1). To run the LISP Editor, one simply types (EDIT)
or (EDIT FOO) to edit the in-core function "FOO" or
(EDIT FOO FOO BAR DSK (COM RPG)) to edit the function
"FOO" in file FOO.BAR in the directory of COM,RPG.
2). (EDIT) or (EDIT FOO) or (EDIT FOO FOO BAR) or (EDIT FOO
FOO BAR DSK (COM RPG)) can be done in LISP's that have
an autoload property for EDIT. Typing (EDIT) causes the
Editor to be initialized and entered. (EDIT1 <exp>) will make
<exp> the toplevel editable expression. (EDIT2 <var>) will
make (PROG2 (SETQ <var> <current value of var>) T) the
toplevel while (EDIT2 (GET <var> <indicator>)) will make it:
(DEFPROP <var> <value> <indicator>).
3). (EDITV <atom>) edits the value of <atom>; the editted expression
is actually (prog1 (setq <atom> <value of atom>) t).
4). (EDITP <atom> <prop>) edits the <prop> property of <atom>; the
actual editted expression is (defprop <atom> <value> <prop>).
How to Look at the Current Expression (CE)
--- -- ---- -- --- ------- ---------- --
P prints the CE using the current print depth
(sublist cutoff) and print length (length cutoff)
PP pretty-prints the entire CE
PS pretty-prints the CE using the print depth cutoff
W prints the "window" surrounding the CE. Thus if
window size is 2, it prints the 2 preceeding and 2 following
tokens around the CE, where "token" means expression or
parenthesis.
(WINDOW n)
changes the window size to n.
(PL n) changes the print length to n (initially 5)
(PD n) changes the print depth to n (initially 2)
Changing the CE
-------- --- --
(CR E1...En) changes the CE to E1...En (i.e. splices in
E1...En), and makes the CE E1.
(n E1...En) n>0, changes the n-th element of the CE to
E1...En
(n E1...En) n<0 changes the n-th element of the CE from the
end to E1...En
(n) n>0 deletes the n-th element of the CE
(n) n<0, deletes the n-th element from the end
RI moves the right parenthesis in one expression
RO moves the right parenthesis out one expression
LI similar to RI
LO similar to RO
DELETE deletes the CE (if the CE is the toplevel
expression, the Editor assumes that the user
wants to edit a different function and requests:
(function name <file specifications>):
The answer can be of several forms; examples:
1) FOO - loads FOO from core
2) (FOO FOO BAR) - loads FOO from FOO.BAR
3) (FOO BAR DSK (COM RPG)) - loads FOO from FOO.BAR in
the directory of COM,RPG.
4) NEW - gives a fresh top-level expression
5) cntrl-G - quits back to the Editor command decoder
6) UNDO - <see below>.
Moving around within the Expression
------ ------ ------ --- ----------
n n>0 makes the new CE the n-th element of the CE
n n<0, makes the new CE the n-th element from the end
of the CE
↑ makes the CE the immediate parent of the CE
TOP makes the CE the toplevel expression
NX makes the CE the next one after the CE
BK makes the CE the one before the CE
MARK marks the current location so that it can be JUMPed
to by the command JUMP. Note: MARKing and JUMPing
is not guaranteed to work in all cases, since
modification of the thing being edited can render
the MARK meaningless.
JUMP jumps to the last MARKed location
UNMARK forgets where the last MARK was set (speeds
execution)
Adding Expressions
------ -----------
(A n E1...En) puts E1...En after the n-th element of the CE
(B n E1...En) puts E1...En before the n-th element of the CE
(AI E1...En) puts E1...En after the CE and makes E1 the new CE
(BI E1...En) puts E1...En before the CE and makes E1 the new CE
(R exp1 exp2) replaces all occurrences of exp1 with exp2 in the CE, viewed
as a list, returns nil? if no occurrences found
(TR exp1 exp2)replaces all occurrences of exp1 with exp2 in the CE, viewed
as a tree
Finding Expressions (i.e. changing the CE)
------- ----------- --- -------- --- --
(F pat) finds the next occurrence of pat, searching in
print order
(BF pat) finds the next occurrence of pat, searching in
inverse print order
(F pat T) finds the next occurrence of pat but looks at the
topmost elements of the CE first (useful for
getting to PROG tags)
(BF pat T) similar to above
(F pat n) finds the n-th occurrence of pat
(BF pat n) similar to above
F finds the next occurrence of the last search
pattern
BF similar to above
Patterns
--------
Pat, as used above, can contain any of the following:
Element of pat What it matches
------- -- --- ---- -- -------
atom atoms EQ to it
list calls matcher recursively
? any atom or single list
(i.e. an s-expression)
?X any element; binds ?X to
whatever it matched
* any non-empty string of
elements
*X matches as *, but binds *X to
the list of elements it matched
=?X whatever ?X matched last time
=*X whatever *X matched last time
(RESTRICT ? P1...Pn) any element satisfying the
predicates P1,...,Pn
($R ? P1...Pn) same as above.
(RESTRICT ?X P1...Pn) similar to above but binds ?X
to what it matched.
($R ?X P1...Pn) same as above.
(⊗R ...) same as ($R ...)
($R * P1...Pn) same as above but the list that * matches
must satisfy P1,...Pn.
($R *X P1...Pn) similar to above
($IR * P1...Pn) similar to above except that Pi is a predicate
that each element of * must satisfy.
($IR *X ...) similar to above
Note: (A ?X IS A ?X) matches (a word is a word) but
not (a word is a sentence). Simlarly for (*X is a *X).
Invoking the Matcher
-------- --- -------
(MATCH pat) attempts to match pat against the CE
(MATCH pat var1 ... varn) attempts to match pat against the
CE while retaining the values of the
variables var1,..., varn. (E.g.
(MATCH (* *A *B ?A) *A ?A).
MATCH attempts to match the last pat against the
CE. Like F and BF above.
REMATCH attempts to get the next match of pat against
the CE. Usually this only makes sense if
pat contains some * variables.
(REMATCH var1 ... varn) rematches but will retain var1,...,varn.
Hairy Matching Uses
----- -------- ----
(PR pat) replaces the CE with the instantiation of
pat (substitutes the values of ?-variables
and *-variables)
(PA n P1...Pn) similar to (A n E1...En)
(PB n P1...Pn) similar to (B n E1...En)
(PAI P1...Pn) similar to (AI E1...En)
(PRA exp1 pat) similar to (R exp1 exp2)
(TPRA exp1 pat) similar to (TR exp1 exp2)
Other Commands
----- --------
(SAVE filename <optional ext>)saves the toplevel expression
in the file given by the file
specs (will create files not
existent),
SAVE saves the toplevel expression
in the file last saved in. If
there was none, the file spec.
is requested.
(REFILE FOO <file specs>) replaces the function FOO in
the file given by the file
specs with that found under
the "draft" property of FOO
where <file specs> is of the
form (file <optional ext>).
(REFILE (FOO1...FOOn)<file specs>)
similar to above but refiles
FOO1...FOOn.
(REFILE (FOO1...FOOn)<infile specs><outfile specs>)
(REFILE * <infile><optional outfile>) updates every function
in infile. Note that the
specs are as file specs in the
vanilla refile above.
similar to above but files the
result in the outfile
REMEMBER puts the toplevel expression
under the "draft" property
(preserves DEFUN format and
comments)
OK REMEMBER's and EVAL's the
toplevel expression
(i.e. defines the function as
well as remembers it)
(COMMENT T) allows comments to be in the
toplevel expression (uses the
grind-read-table)
(COMMENT NIL) disables above
HELP either provides helpful
information or confuses you
The Undo Feature
--- ---- -------
The Editor allows the user to "undo" any editing he has
done. Thus if he has made a mistake or simply is
experimenting, he can invoke the undo feature to undo each
step. However the undoer requires a history of the edit to
be kept and so uses a lot of space. Be warned!
(UNDO T) enables undoing
(UNDO n) enables undoing with only the last undoable
commands being saved (initially 6.)
(UNDO NIL) disables undoing and flushes the undoqueue (the
history)
UNDO undoes the last command. Successive UNDO's will
undo prior edit commands.
The following commands can be undone:
↑ TOP RI RO LI LO NX BK BF DELETE F OK REMEMBER (COMMENT
-) (A -) (B -) (R -) (PA -) (PB -) (PAI -) (PBI -) (PL -)
(PD -) (PRA -) (BF -) (F -) (CR -) (PR -) (AI -) (BI -)
(N -) (N) N (EDPROG -).
Programming the Editor
----------- --- ------
***** Flushed 12/4/76 *****
(EDPROG T) enables the " read-macro
(EDPROG NIL) disables above
***** End Of Flush *****
(EDITCOMMAND A B) a FEXPR which allows the atom A to mean
B in the Editor. For instance,
(EDITCOMMAND LEN (LENGTH %#CE))
tells the Editor that when you type LEN
to it, the length of the CE is to be
reported.
It is possible to write LISP programs to do editing:
one can cause the editor to evaluate a command by saying:
(%EVALUATE exp), where exp must EVAL to a valid edit
command. A simple way to abbreviate these calls to the
editor is to define a read macro which expands to the
desired call.
One may also have an initialization file called
EDIT.INI which will be read when the Editor is being loaded.
This file can either contain functions like any other LISP
file or LINKTO statements, which are of the form:
(LINKTO (<filespec1>)(<filespec2>)...)
This statement will cause the Editor to read the files
specified in order. Functions and LINKTO statements may be
interspersed. No FASLOADs may occur in the initialization
file nor in any of the files LINKTOed.
A nice subset of an EDIT.INI file can be seen in
EDIT.IN[AID,RPG] which is documented in
FASMAC.DOC[AID,RPG]. Basically it uses a hoakey fast read
macro facility and allows one to use the control/meta keys
as fast macros to do atomic edit commands with a minimum of
key strokes.
The following global variables are useful:
%#CE contains the CE (munging the CE must be done
using the Editor)
%TOP-EDIT-EXP contains the toplevel expression
%#UNDOLIST contains the undolist
%#UNDOFLAG tells whether or you you are in the undo mode
Exiting and Etc.
------- --- ---
EXIT exits the Editor (to the LISP toplevel)
(EDIT) gets you back to the Editor
(REMEDIT) flushes the Editor.
Any other command is handed to LISP to be EVAL'ed.
The Backspace (BS) Package
--- --------- ---- -------
This package, written by Jonl White at the MITAI Lab,
is useful for exploring the environment of a LISP error; it
makes use of the EVALFRAME feature documented in the MACLISP
Reference Manual (from here on referred to as the "MACLISP
Manual").
When one is in the (*RSET T) mode, a record is kept of
the forms and binding environments which lead to the current
envirnoment. when an error occurs the BS functions allow
the user to examine those environments without jeopardizing
the current state. The BS functions can be loaded by doing:
(FASLOAD BS FAS DSK (MAC LSP))
and is initialized by:
(SETUP)
which puts LISP in the (*RSET (NOUUO T)) mode.
When a break occurs, one can initialize the environment
stack with:
(BS NIL).
At this point one can start backspacing; successive calls
to (BS) will print the form whose evaluation caused the
evaluation of the current form. Moreover, the printed form
is stored as the value of the atom BS.
Suppose the break has been caused because the atom "x"
is unbound; then the evaluation of "(BS NIL)" will cause
the following to be printed:
(APPLY -1273734574 (EVALFRAME (NIL)) -725732747)
The next evaluation of (BS) will cause:
(EVAL -1302734603 (BS) -725732747)
One more (BS):
(APPLY -1345734646 (+INTERNAL-UBV-BREAK ((X))) ..)
Finally (BS) yields:
(EVAL -1372734673 X -755732777)
In the above forms, the first element is either EVAL or
APPLY, the second is a pdl-pointer specifying flow of
control, the third is the form whose evaluation (or
application) is about to be attempted, and the last element
is an a-list pointer specifying the binding environment.
Note that the use of these pointers is explained in the
MACLISP Manual under the heading "Debugging Aids in LISP".
Successive (BS)'s will go up one level while (FS) will
go down one level (where "up" is backwards in time or down
the stack, and "down" is forwards in time or up the stack).
A summary of the available commands:
(BS) Backspace 1 level
(BS n) Backspace n levels
(BS <function-name>) Backspace to the first call to
function-name
(BS NIL) Initialize to the top of the
pdl stack (furthest ahead in
time) and (BS) n times
(BS nil <fn>) Initialize and do (BS <fn>)
(BS NIL <fn> n) Initialize and do (BS <FN> N)
(FS) Go forward (ahead in time) 1
level
(FS NIL) Initialize to the bottom of the
pdl stack (furthest back in
time)
(FS NIL n) Initialize and do (FS n)
When in some environment which one would like to
explore, the following is useful:
↑B
<form1>
.
.
.
<formn>
which evaluates each <formi> in the current binding environment
using the last element of the form printed by (BS) and the
optional second argument to EVAL.
Finally cntrl-G quits back to the LISP toplevel from
the break condition.
The BRAKE Package
--- ----- -------
This package is useful for putting breakpoints in a
function with minimal effort; the functions to be described
use the Editor (see above) and should not be used unless the
Editor is present. In fact, these functions use the Editor
to add the breakpoints.
Basically there are only five functions: BRAKE,
UNBRAKE, BRK, UNBRK, and BRAKEIF (all FEXPRs). The arguments
to BRAKE are:
which function
where in the function to put the breakpoint
under what conditions the break should be executed.
These arguments are specified by putting
indicator-value pairs in the argument positions of the
function BRAKE. Example:
(BRAKE IN QUUX AFTER (SETQ *) NUMBER 3 IF (EQ N 4))
which says to put a breakpoint in the function QUUX
after the third SETQ and to actually break if n=4. Note
that these pairs can be in any order since the function
treats its arguments much like a property list. Thus we
could have said:
(BRAKE NUMBER 3 AFTER (SETQ *) IF (EQ N 4) IN QUUX).
Moreover not every one of these pairs is necessary
since defaults are available:
MISSING ASSUMED
------- -------
IN the current function being edited
IF IF T
NUMBER NUMBER 1
AFTER none
BEFORE nONE.
Therefore
(BRAKE AFTER (SETQ A *))
is legal. To remove all of the breakpoints from FOO, one
does:
(UNBRAKE FOO)
and if FOO is the function being Edited:
(UNBRAKE)
(Note: after BRAKE and UNBRAKE the CE is the topmost
expression of the function where the breakpoint was
installed).
The forms of the breakpoints are as follows:
(BRAKE IN <name>
AFTER <pattern> NUMBER n IF <pred>)
yields
(PROG2 NIL <form>
(BREAK (IN <name> AFTER <pattern> NUMBER n)
<pred>)).
,and
(BRAKE IN <name>
BEFORE <pattern> NUMBER n IF <pred>)
yields
(PROG2
(BREAK (IN <name> BEFORE <pattern> NUMBER n)
<pred>) <form>).
where <form> is the n-th form to match <pattern> using the
Editor matcher. UNBRAKE only removes breakpoints of this
form.
BRAKE with no arguments returns a list of all broken
functions (i.e. those broken using either BRAKE or BRK.
BRK puts breakpoints at the beginning of functions;
these breakpoints are invoked each time the function is
called (i.e. there is no associated predicate). The call to
BRK looks like (BRK <fn1> <fn2> ... ), where none of <fni>
are evaluated.
UNBRK removes the initial breakpoint from each of its
unevaluated arguments. If no arguments are specified, all
functions which have had breakpoints installed using BRK
will be un-broken.
BRAKEIF is a fexpr which takes a function and a
predicate of no arguments. The function will invoke the
break whenever the function is called and the predicate is
true.
THE DEBUG PACKAGE
--- ----- -------
This package contains two functions, DEBUG and BT,
which allow the user to examine LISP's stack (also refered
to as the PDL or Push-Down-List). If the global LISP
variable *RSET is set to T, then the stack will contain a
detailed record of all the S-expressions currently in the
process of evaluation. The user should be aware that when
*RSET is bound to T, LISP runs more slowly and uses more
list storage space.
The lexpr DEBUG enables one to explore expressions on
the stack, examine local variable bindings, and force a
partially evaluated expression to prematurely return a
specified value. The function BT displays an indented
version of the "backtrace".
Using DEBUG
----- -----
(DEBUG T) - Causes LISP to enter debugging mode by
setting *RSET and NOUUO to T and snapping
the "UUO links".
(DEBUG NIL) - Sets *RSET and NOUUO to nil to leave
debugging mode (resulting in faster and more
efficient evaluation).
(DEBUG) - Enters the debugging function. DEBUG will
print the last S-expression that LISP was
trying to evaluate and wait for a command
character to be entered. After executing
the command, DEBUG will wait for a new
command to be entered. Any of the commands
can be preceeded be an arbitrary positive
integer, <n>, which will cause that command
to be executed <n> times.
Commands To Change the Current Expression
-------- -- ------ --- ------- ----------
DEBUG keeps a pointer to an element of LISP's stack,
the "current expression" or CE. One set of commands are
provided to move this pointer, each time displaying the new
CE. The user can refer to the CE (for example, within
breakpoints while DEBUGging) with the variable %CE
D - move Down the stack.
This command makes the CE the next lower
S-expression on the stack (i.e. moving us backward
thru time).
U - move Up the stack.
This command makes the CE the next higher
expression on the stack (i.e. forward thru time).
T - jump to the Top of the stack.
This command makes the CE the expression on the
top of the stack (i.e. the last expression being
evaluated before the call to DEBUG).
Commands to Exit the DEBUG function
-------- -- ---- --- ----- --------
Q - Quit
This command exits from the debugging function,
leaving the user in the same state he was in
before doing (DEBUG).
R - Return value.
This command forces the current expression to
return a specified value. The user is first asked
to verify that he wants to force a return from the
current expression. If so, he is asked for a form
to be returned. This form is evaluated and used
as the return value for the CE.
C - Re-evaluate current expression.
This is a variation of the R command in which the
current expression is re-evaluated. The user is
asked to verify that he wants the current
expression to be re-evaluated.
Other Commands
----- --------
P - Print the current expression.
DEBUG normally displays expressions with a
PRINLEVEL of 3 and a PRINDEPTH of 5. This command
is used to display the current expression in its
entirety.
S - Sprint the CE.
This command "pretty-prints" the CE.
B - Break
This command causes LISP to break in the
environment of the current expression. This
allows the user to examine local variable bindings
To continue DEBUGing, the user should type a "$P".
? - Help
This command prints the list of the commands.
A Sample DEBUGing Session
- ------ -------- -------
In this commented LISP session, lines entered by
the user are preceeded by a "*".
*(DEFUN FACT (X) ;POOR LOSER TYPES HIS
(COND ((= X 0.) I) ; PROGRAM WRONG!
(T (* X (FACT (1- X))))))
*(DEBUG T) ;ENTER DEBUGGING MODE
T
*(FACT 6) ;TRY FUNCTION
I UNBOUND VARIABLE
;BKPT UNBND-VRBL
*(DEBUG) ;CALL DEBUGGING FUNCTION
(+INTERNAL-UBV-BREAK ((I))) ;LAST THING LISP EVAL'ED
*D ;MOVE DOWN THE STACK
I ;NEXT FORM ON STACK
*D ;MOVE DOWN AGAIN
(COND ((= X 0.) I)(T (* X (FACT (1- X)))))
*D
(FACT (1- X))
*D
(* X (FACT (1- X)))
*T ;JUMP TO TOP OF STACK
(+INTERNAL-UBV-BREAK ((I)))
*D ;AND MOVE DOWN ONE
I
*B ;BREAK IN LOCAL ENVIRONMENT
;BKPT DEBUG
*(BOUNDP 'I)
NIL
$P ;RETURN FROM BREAKLOOP.
;$P is <altmode>P
I ;DEBUG DISPLAYS CE AGAIN
*R ;FORCE A RETURN FROM CE
FORCE RETURN FROM CURRENT EXPRESSION?
TYPE YES OR NO: YES
>>>WHAT SHOULD THIS S-EXPRESSION RETURN? 1.
240. ;RETURN VALUE OF (FACT 6)
The BT Function
--- -- --------
The lexpr BT is used to display a backtrace of the
function calls leading up to the S-expression being
evaluated before a break. Calling BT with no arguments will
cause an indented list of all function calls on the stack to
be printed. If BT is given an optional numeric argument, n,
only the last "n" function calls will be displayed.
BT does not display internal calls used by STEP, the
sinlge stepper discussed below.
The following example uses our losing FACT function.
Again, the users input is prefaced with a "*".
*(DEBUG T) ;WE MUST BE IN *RSET/NOUUO MODE
T ; FOR (BT) TO WORK
*(FACT 6)
I UNBOUND VARIABLE
;BKPT UNBND-VRBL
*(BT)
FACT
COND
TIMES
FACT
COND
TIMES
FACT
COND
+INTERNAL-UBV-BREAK
*
Using DEBUG with STEP
----- ----- ---- ----
DEBUG knows about the Stepper, and will not print any
information put on the stack by STEP.
THE STEP PACKAGE
--- ---- -------
This package contains three fexprs, STEP, STEP-HARD,
and BREAKIF, which make use of the EVALHOOK function in
MACLISP. The STEP function provides a single stepping
facility in which LISP displays each form before it is
evaluated. Additional features are provided to selectively
enable single stepping mode (e.g. only within calls to
certain functions) and to create "LISP demons". Demons can
also be created with the BREAKIF function.
Simple use of the STEP function
------ --- -- --- ---- --------
The simplest way to use the STEP function is as follows:
(STEP T) - Enter single stepping mode immediately.
(STEP NIL) - Exit single stepping mode.
In single stepping mode, LISP will display each form
before evaluation and pause to accept a command character
from the user. When the form is completely evaluated, its
return value is displayed. The commands are:
⊗S - Evaluate this form in single stepping
mode.
⊗X - "Skip". Do not evaluate this form in
single stepping mode. Single stepping
mode will be resumed after this form is
evaluated. If a break is encountered,
(STEP T) will work.
⊗M - Like ⊗S except it treats the current form
as a macro and expands the form without
any intermediate stepping.
⊗V - Like ⊗X but performs the expression in
*rset = nil mode.
⊗Z - "Skip". Do not evaluate this form in
single stepping mode. Single stepping
mode will be resumed after this form is
evaluated. If a break is encountered,
(STEP T) will not work.
⊗Q - "Quit". Exit single stepping mode.
⊗C - "Continue". Continue evaluation without
stepping until the next AFTER or
WHEREIN clause is true.
⊗P - Pretty-print the current form.
αP - Reprints the current form with prinlength
and prinlevel increased by one.
βP - Same as above.
⊗B - Breaks STEP at current depth. %CE contains the
current expression
Where "⊗" means control-meta, "α" means control, and "β"
means meta. Typing a ↑G ("control-G") at any time will
cause LISP to leave single stepping mode. The stepper stores
in the global variable %CE, the s-expression currently under
consideration.
One can modify the default prinlevel and prindepth for
the Stepper by setting the global variables STEP-PL and
STEP-PD, currently set to 4 and 3 resp.
An Example
-- -------
Lines typed by the user are preceeded by a "*".
*(SETQ X 5.)
5.
*(STEP T) ;ENTER SINGLE STEPPING MODE
(T)
*(* X (1+ X) (1- (* X X X))) ⊗S ;FORM TO BE EVALED
X = 5.
(1+ X) ⊗S
X = 5.
6.
(1- (* X X X)) ⊗S
(* X X X) ⊗X ;COMMAND: SKIP SINGLE STEPPING
125. ; ON THIS FORM.
124.
3720.
3720.
(STEP NIL) ;EXIT SINGLE STEPPING MODE
Advanced Features
-------- --------
The STEP function can be instructed to selectively turn
on single stepping mode only after a particular function has
been called or only within calls to certain functions. STEP
can also be used to create arbitrary "demons" which can
cause LISP to stop and enter a break loop. This is done by
giving STEP from one to three clauses, for example:
(STEP <clause> <clause> <clause>)
where the clauses can be one of the following:
(AFTER FN1 FN2 FN3 ...)
Causes LISP to enter single stepping mode only
after one of the functions FN1, FN2, etc. has
been called.
(WHEREIN FN1 FN2 FN3 ...)
Causes LISP to evaluate in single stepping mode
only within calls to the functions FN1, FN2, etc.
(BREAKIF FORM1 FORM2 ...)
Will cause the S-expressions FORM1, FORM2, etc.
to be evaluated just before every S-expression is
evaluated. If any of these demons evaluate to
non-NIL, LISP will enter a break loop. When the
user exits the break loop (with a $P) he will be
asked if he wishes this demon to remain active, or
be removed from the demon-list. Evaluation then
proceeds in the normal manner.
(E-STEP (FN A1 ...AN)) sets up to step wherein FN and
then evals (FN A1 ...AN).
(UNSTEP (WHEREIN ...)) and (UNSTEP (AFTER ...)) undo
the above.
(STEP fn1 fn2 ...) defaults to (step (wherein fn1
fn2...)). (UNSTEP fn1 fn2 ....) defaults to (UNSTEP (wherein
fn1 fn2 ...)).
The user can cause these clauses default to their last
specified values by evaluating (STEP *). This is very
useful if one has left single stepping mode with a "↑G".
Using STEP with TRACE
----- ---- ---- -----
If the Stepper ever needs to step through a function
which is being traced, the Stepper will first UNTRACE that
function.
Using STEP with Breakpoints
----- ---- ---- -----------
If you are evaluating in single stepping mode and enter
a breakpoint loop, LISP will not be in single stepping mode
in that loop. Conversely, if LISP is not in single stepping
mode at the top level, and you evaluate (STEP T) inside a
break-loop, it will have no effect on top level evaluation.
In order to enter single stepping mode from a breakpoint,
the user can evaluate (STEP) at the top level. This puts
the single stepper in a mode where the user can turn it on
from within a break loop.
The BREAKIF Function
--- ------- --------
An additional function, the fexpr BREAKIF, can also be
used to set up LISP demons. This function looks like the
BREAKIF clause in the STEP function. Evaluating:
(BREAKIF FORM1, FORM2, ... )
will set up FORM1, FORM2, etc. as demons, and evaluating:
(BREAKIF NIL)
will disable all the demons. As with STEP, typing a ↑G will
also disable the demons. Creating demons with BREAKIF is
somewhat more efficient than using the STEP function,
however, it can not be used in single stepping mode.
Step Hard Feature
---- ---- -------
The feature: (step-hard ...) is just like step EXCEPT
it works HARDER! Now, working harder is really a fact, so
don't use it unless you need it. Here's what it does:
suppose you have (defun foo (n) ... (bar ...) ...) and foo
is compiled and bar isn't, and you want to step wherein bar.
Well, since eval never sees the compiled call to bar, if you
are stepping-hard, the stepper looks around the FIRST chance
it gets to see if it is inside of BAR. Now, this means it
searches the control stack; if it is in bar it prints
<in BAR>
next-form.
A Summary
- -------
(STEP T) - Enter single stepping mode.
(STEP NIL) - Disable single stepping mode.
(STEP <CLAUSE>) - Selective single stepping and/or demons.
(STEP *) - As above, but use defaults (last
specified clauses).
(STEP) - Enable single stepper so that it can be
turned on from within a break loop.
(BREAKIF F1...) - Sets up demons F1, ... .
(BREAKIF * ) - Re-enables last specified set of demons.
(BREAKIF NIL) - Disables demons.
(STEP-HARD <CL>)- Like STEP, but works harder.
<control>G - Exits single stepping/demon mode.
Features and Meta-features
-------- --- ---- --------
The Maclisp at SAIL contains several autoload-able
initial functions of use in debugging. First, EDIT has the
autoload property, and thus the Editor may be run at any
time. Second, there is a function of no arguments called
HELP, which is autloadable. This function merely serves to
load HELP.FAS[MAC,LSP], which is a file of autoload
properties for various functions. Among these functions are:
DEBUG, BT Debug routines discussed above
STRING Readmacro for " (equivalent to |)
MACRO, MACRODEF Macro definition macros
MACROBIND
PRLISP, PRECESS Prlisp package from MIT
MACEX File macro expansion package, useful
for preparing Maclisp files to run under
Interlisp
STEP, BREAKIF Step package discussed above.
STEP-HARD
REVIEW, INDEX MIT indexing program
INPUSH,INPOP File requiring routines.
REQUIRE (INPUSH and INPOP are OLDIO functions only)
SETUP Jon White Backspace Package.
CGOL Pratt's CGOL.
BRAKE, BRK, Brake package discussed above
UNBRAKE, UNBRK,
BRAKEIF
TRACEQ SETQ tracer.
DIR, DIRECT, Directory package, including > hack routines
UGREAT
ET Routines to run E as a subjob
MAIL Routines to MAIL from Maclisp
LOADCR,LOADED Line editor loading routines
ADDED, INITED
String
------
The string macro simply allows the user to use "
wherever | is appropriate in normal Maclisp.
Macrodef
--------
MACRODEF is a macro used to define macros! The two
normal ways of using it are with parenthesized and
unparenthesized arguments (like exprs and lexprs). With
parenthesized arguments, the individual formal arguments
have the corresponding actual arguments substituted for them
in the body of the macro. For instance, one might want to
have a macro to do simple stack manipulations, where the
underlying implementation is in terms of lists. So, we might
have:
(MACRODEF PUSH (THING PDL) (SETQ PDL (CONS THING PDL)))
(MACRODEF POP (PDL) (PROG2 NIL (CAR PDL) (SETQ PDL (CDR PDL))))
Code using these macros would be something like:
Macro call Expansion
----- ---- ---------
(PUSH (PLUS FOO BAR) QUUX) ===> (SETQ QUUX (CONS (PLUS FOO BAR) QUUX))
(POP QUUX) ===> (PROG2 NIL (CAR QUUX) (SETQ QUUX (CDR QUUX)))
where the forms on the right are the results of the
macro-expansion (i.e. the actual code executed).
With an unparenthesized argument, the single argument
is bound to the CDR of the calling form, and that form is
then substituted for the formal argument throughout the body
of the macro. Thus:
(MACRODEF PROG1 X (PROG2 NIL . X))
is a macro to do the obvious thing for PROG1's. Notice
particularly that the "." situation is handled correctly.
MACRODEF's with more than one form in the body are
handled by adding an explicit PROGN if necessary. Finally,
remember that substitutions for formal parameters is done,
not lambda-binding. So arguments are re-computed wherever
their formal parameters appear in the defining form. To
solve this problem, one can explicilty lambda-bind. Macros
within MACRODEF's are allowed.
MACRODEF with parenthesized name (i.e. (macrodef (foo) ...)) will
create a compilable macro.
MACRO
-----
MACRO is another macro definition macro, but allows for
fancier argument handling. Used in conjunction with CODE,
this definition facility permits the programmer wide
latitude in defining his syntactic sugar. The binding
mechanism used is based on the Editor's pattern matcher
discussed above: one can invoke the pattern matcher on the
CDR of the responsible form. The side effects of this
process (namely, setting ? and * variables) can be used by
CODE to produce code based on the input in a convenient
manner. For example, here is a macro to do lambda-binding in
a more readable format:
(macro let (*vars ← *vals do *form)
(code ((lambda (*vars) *form) *vals)))
An example of the use is:
(let foo bar quux ← (plus x y z) 'foo quux do
<hack foo, bar, and quux>)
===> ((lambda (foo bar quux)
<hack foo, bar, and qquux>)
(plus x y z) 'foo quux)
CODE, a FEXPR, is simply the instantiation mechanism
talked about in the Editor section. CODE takes a form, and
replaces all occurrences of variables whose first character
is ? with its LISP value. All forms with * as their first
character have their values (lists) spliced in wherever they
occur in the form. Here's an example of this facitlity
defining a hairy FOR loop:
;;; (FOR X {IN,ε} L {DO,APPEND,COLLECT,CONC,SELECT} form {RETURN} form)
(macro for (*x ($r ? (lambda(q) (memq q '(in ε)))) *l ($r ?verb (lambda (q)
(memq q '(do collect append conc select)))) *form)
((lambda (*form1 *form2)
(%match '(*form1 return *form2) *form)
(cond ((eq ?verb 'append)
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
((lambda (q) (cond (q (ncons q))))
(progn *form1)))) *l) *form2)))
(t (code (mapcan (function (lambda(*x)((lambda(q)(cond (q (ncons q))))
(progn *form1)))) *l)))))
((eq ?verb 'conc)
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
(progn *form1))) *l) *form2)))
(t (code (mapcan (function (lambda (*x)
(progn *form1))) *l)))))
((eq ?verb 'select)
(cond (*form2
(code (progn (mapcan (function (lambda (*x)
(and *form1 (list *x)))) *l)
*form2)))
(t (code (mapcan (function (lambda (*x)
(and *form1 (list *x)))) *l)))))
(t ((lambda (?verb)
(cond (*form2
(code (progn (?verb (function (lambda (*x) *form1)) *l) *form2)))
(t
(code (?verb (function (lambda (*x) *form1)) *l) ))))
(cond ((eq ?verb 'do) 'mapc)
(t 'mapcar))))))
*form nil))
MACRO with a parenthesized name will create a compilable macro ala MACRODEF.
Further MACRO/MACRODEF features
------- -------------- --------
There are some additional features associated with
these macro definition facilities. First of all, normal
macro expansion is destructive; that is, the form causing
macro expansion is actually replaced (via RPLACA and RPLACD)
so that the subsequent passes over the code does not cause
re-expansion. However, secondly, in *RSET T mode,
destructive expansion is inhibited, so while DEBUGging or
STEPping, one can see both the call on the macro and on the
expanded code.
In addition, if the global variable SAVE-MACROS is
non-nil, then the original form and its expansion are stored
somewhere so that (UNCAN) will un-expand all macros.
%%CLOBBER-MACROS%% will cause destructive macros to
destroy regardless of *REST.
MACEX
-----
MACEX, a FEXPR, expects an EREAD style file
specification as its argument and produces a file with all
known macros expanded as a side effect. The extension of the
file produced is .EXP on the aliased directory. MACEX
attempts to understand REQUIRE's, but is not guaranteed to
work in all hairy cases. A tactic useful in such cases is to
MACEX the file(s) in question from within a core image with
the file(s) loaded (and with all the macros defined, of
course). E.g. (MACEX FOO BAR DSK (AID RPG)).
REQUIRE
-------
REQUIRE is a FEXPR taking a file specification and
having the effect of splicing that file stream in at the
point of call. Actually, REQUIRE pushes the state of the
file open on channel 3, PRINT-EVAL-READs each form in the
file given by its arguments, and finally pops back to the
old file. Nesting to 23 levels is permitted (SAIL monitor
restriction). REQUIRE looks at the value of the global
variable READ, and uses the function pointed to rather than
READ if it is non-nil. The file specification is the same
as that expected by EREAD.
INPUSH is a FEXPR which takes a file specification and
pushes the state of the file open on channel 3 and positions
the read pointer to the first non-E directory item in the
file specified. This function is used by REQUIRE.
INPOP is an EXPR of no arguments which restores the
file state to that just after the point of call of the last
INPUSH EVALed. This function is used by REQUIRE. These
functions are in OLDIO only.
DIRECT
------
DIRECT is an EXPR of two arguments. The first argument
is a project, and the second is a programmer. The result is
a list of files in the directory specified by the ppn. For
example, (DIRECT 'AID 'RPG) returns a list such as:
((edit /113) (option txt)...)
DIR is a FEXPR taking either a full ppn spec, just the
project, or no ppn spec and performs a DIRECT on the
specified directory. If no programmer is pecified, the the
logged in programmer is assumed. If no specification is
given, then the aliased ppn is assumed.
UGREAT is a FEXPR taking three arguments: a file name
(no extension), a project, and a programmer, and returns the
highest numbered extension for that file name in the
directory specified. No defaulting is performed.
ET
--
ET is an LEXPR expecting a file specification and two
optional arguments, a page number and a line number. The
file specification is of the form (file ext (p pn)) and all
but the file are optional. The function causes E, the SAIL
editor to be run on the specified file and the cursor to be
positioned at the designated page and line. If no line is
given, the top of the page is assumed; if no page is given,
page 1 is assumed. αXrun (α = control) causes the Maclisp to
be resumed.
MAIL
----
MAIL is a FEXPR expecting two arguments, a destination
and a message. The destination is an atomic symbol
specifying a programmer (i.e. RPG) and the message is a
string (i.e. |Hello, Ralph| or "Hello, Chump"). If the
message or both arguments are missing, MAIL prompts for
them. MAIL uses the MAIL phantom, and so does not deliver
immediately (neither does the Post Office, though).
Note that the arguments to MAIL are EVALed internally
unless they are prompted for!
Line Editor Loading
---- ------ -------
INITED is an EXPR of no arguments which initializes an
internal buffer (must be done initially)
ADDED is an EXPR of two arguments, a form and a flag.
If the flag is nil, then the form is put in the internal
buffer without slashifying special characters. If the flag
is non-nil, special characters are slashified.
LOADED is an EXPR of no arguments, and loads the
contents of the internal buffer into the line editor.